package com.zxy.ziems.server.board.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.zxy.btp.common.exception.ConditionException;
import com.zxy.ziems.server.board.constant.MysqlDateFormatEnum;
import com.zxy.ziems.server.board.pojo.vo.DosageVo;
import com.zxy.ziems.server.board.pojo.vo.EnergyTrendVo;
import com.zxy.ziems.server.board.service.EvBoardService;
import com.zxy.ziems.server.classify.pojo.entity.ClassifyDeviceProperty;
import com.zxy.ziems.server.classify.service.ClassifyDevicePropertyService;
import com.zxy.ziems.server.constant.DateType;
import com.zxy.ziems.server.constant.enums.DictCodeEnum;
import com.zxy.ziems.server.domain.DictItem;
import com.zxy.ziems.server.energy.mapper.DeviceMeasureDataDayMapper;
import com.zxy.ziems.server.energy.mapper.DeviceMeasureDataIncrementHourMapper;
import com.zxy.ziems.server.energy.mapper.DeviceMeasureDataMapper;
import com.zxy.ziems.server.service.DictItemService;
import com.zxy.ziems.server.utils.BusinessExceptionUtil;
import com.zxy.ziems.server.utils.DateUtils;
import com.zxy.ziems.server.vo.ChartVo;
import com.zxy.ziems.server.vo.ChartYAxisVo;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class EvBoardServiceImpl implements EvBoardService {

    @Autowired
    private DictItemService dictItemService;
    @Autowired
    private ClassifyDevicePropertyService classifyDevicePropertyService;
    @Autowired
    private DeviceMeasureDataMapper deviceMeasureDataMapper;
    @Autowired
    private DeviceMeasureDataIncrementHourMapper deviceMeasureDataIncrementHourMapper;
    @Autowired
    private DeviceMeasureDataDayMapper deviceMeasureDataDayMapper;

    @Override
    public List<DosageVo> currentValue() {
        List<DosageVo> res = new ArrayList<>();

        // 获取字典配置
        List<DictItem> dictItems = getDictConfig();

        // 获取配置类属性
        List<ClassifyDeviceProperty> classifyDeviceProperties = classifyDevicePropertyService.getByClassIds(dictItems.stream().map(DictItem::getItemCode).collect(Collectors.toList()));

        // 获取设备参数当前值
        res = deviceMeasureDataMapper.getLastVal(classifyDeviceProperties.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toList()),
                classifyDeviceProperties.stream().map(ClassifyDeviceProperty::getDataTypeId).collect(Collectors.toList()));

        return res;
    }

    /**
     * 获取环保字典配置
     * @return
     */
    @NotNull
    private List<DictItem> getDictConfig() {
        List<DictItem> dictItems = dictItemService.getByDictCode(DictCodeEnum.EV_BOARD.getCode());
        if (CollectionUtil.isEmpty(dictItems)) {
            throw BusinessExceptionUtil.exception("环保分类未配置");
        }
        return dictItems;
    }

    @Override
    public EnergyTrendVo classTrend(String dateType) {
        EnergyTrendVo res = new EnergyTrendVo();

        switch (dateType) {
            case DateType.DAY -> getDayData(res);
            case DateType.MONTH -> getMonthData(res);
            case DateType.YEAR -> getYearData(res);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }

        return res;
    }

    private void getYearData(EnergyTrendVo res) {
        // 获取最近30天数据
        List<String> lastDay = DateUtils.getLastMonth(LocalDateTime.now(), 12);
        LocalDateTime startDate = DateUtils.toDateTime(lastDay.get(lastDay.size()-1) + "-01", DateUtils.YMD_PATTERN);
        LocalDateTime endDate = DateUtils.getEndTime(LocalDate.now());

        // 获取字典配置
        List<DictItem> dictItems = getDictConfig();

        // 获取配置类属性
        List<DosageVo> dosageVos = deviceMeasureDataDayMapper.classTrend(startDate, endDate, dictItems.stream().map(DictItem::getItemCode).collect(Collectors.toList()), MysqlDateFormatEnum.YY_D.getFormat());

        processData(res, lastDay, dictItems, dosageVos);
    }

    private void getMonthData(EnergyTrendVo res) {
        // 获取最近30天数据
        List<String> lastDay = DateUtils.getLastDay(LocalDateTime.now(), 30);
        LocalDateTime startDate = DateUtils.toDateTime(LocalDate.now().getYear() + "-" + lastDay.get(lastDay.size()-1), DateUtils.YMD_PATTERN);
        LocalDateTime endDate = DateUtils.toDateTime(LocalDate.now().getYear() + "-" + lastDay.get(0), DateUtils.YMD_PATTERN);

        // 获取字典配置
        List<DictItem> dictItems = getDictConfig();

        // 获取配置类属性
        List<DosageVo> dosageVos = deviceMeasureDataDayMapper.classTrend(startDate, endDate, dictItems.stream().map(DictItem::getItemCode).collect(Collectors.toList()), MysqlDateFormatEnum.M_D.getFormat());

        processData(res, lastDay, dictItems, dosageVos);
    }

    private void getDayData(EnergyTrendVo res) {

        // 获取最近一天数据
        List<String> lastDayHour = DateUtils.getLastDayHour(LocalDateTime.now());
        LocalDateTime startDate = DateUtils.toDateTime(lastDayHour.get(lastDayHour.size()-1), DateUtils.YMD_H_PATTERN);
        LocalDateTime endDate = DateUtils.toDateTime(lastDayHour.get(0), DateUtils.YMD_H_PATTERN);

        // 获取字典配置
        List<DictItem> dictItems = getDictConfig();

        // 获取配置类属性
        List<DosageVo> dosageVos = deviceMeasureDataIncrementHourMapper.classDayTrend(startDate, endDate, dictItems.stream().map(DictItem::getItemCode).collect(Collectors.toList()));
        processData(res, lastDayHour, dictItems, dosageVos);
    }

    private static void processData(EnergyTrendVo res, List<String> dateList, List<DictItem> dictItems, List<DosageVo> dosageVos) {
        Map<String, List<ChartVo>> energyTrend = new HashMap<>();
        Map<String, List<DosageVo>> classifyMap = dosageVos.stream().collect(Collectors.groupingBy(DosageVo::getClassifyName));

        for (DictItem dictItem : dictItems) {
            List<ChartVo> value = new ArrayList<>();
            ChartVo chartVo = new ChartVo();
            List<String> xAxisList = new ArrayList<>();
            chartVo.setXAxisList(xAxisList);

            List<DosageVo> classDosageVos = classifyMap.get(dictItem.getItemCode());
            Map<String, BigDecimal> valMap = new HashMap<>();
            if (!CollectionUtil.isEmpty(classDosageVos)) {
                valMap = classDosageVos.stream().collect(Collectors.toMap(DosageVo::getName, DosageVo::getValue));
            }
            List<ChartYAxisVo> yAxisList = new ArrayList<>();
            ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
            chartYAxisVo.setName(dictItem.getItemName());
            List<BigDecimal> data = new ArrayList<>();
            for (int i = dateList.size() - 1; i >= 0; i--) {
                String day = dateList.get(i);
                BigDecimal bigDecimal = valMap.get(day);
                xAxisList.add(day);
                data.add(bigDecimal == null ? BigDecimal.ZERO : bigDecimal);
            }

            chartYAxisVo.setData(data);
            yAxisList.add(chartYAxisVo);
            chartVo.setYAxisList(yAxisList);
            value.add(chartVo);
            energyTrend.put(dictItem.getItemName(), value);
        }

        res.setEnergyTrend(energyTrend);
    }

}
